//
// GPSMapEdit
// (c) Konstantin Galichsky (kg@geopainting.com), 2007
//
// Set of adjustable colors.
//

# include "StdAfx.h"
# include "Resource.h"
# include "Colors.h"
# include "Settings.h"
# include "Globals.h"

void CColors::SetColors (const COLORREF * _pColors, size_t _cColors) {
	_DestroyColors ();

	m_colors.resize (_cColors);
	for (size_t c = 0; c < _cColors; ++ c) {
		color_t & col = m_colors [c];
		col.col  = _pColors [c];
		col.hbr  = NULL;
		col.hpen = NULL;
	}
}

void CColors::_DestroyColors () {
	const size_t cColors = m_colors.size ();
	for (size_t c = 0; c < cColors; ++ c) {
		const color_t & col = m_colors [c];
		if (col.hbr)
			::DeleteObject (col.hbr);
		if (col.hpen)
			::DeleteObject (col.hpen);
	}

	m_colors.clear ();
}

void CColors::SetColor (size_t _cIdx, COLORREF _col) {
	assert (_cIdx < m_colors.size ());
	if (_cIdx >= m_colors.size ())
		return;
	color_t & col = m_colors [_cIdx];

	if (col.hbr)
		::DeleteObject (col.hbr);
	if (col.hpen)
		::DeleteObject (col.hpen);

	col.hbr  = NULL;
	col.hpen = NULL;
	col.col  = _col;
}

HBRUSH CColors::GetBrush (size_t _cIdx) const {
	HBRUSH & hbr = m_colors [_cIdx].hbr;
	if (hbr == NULL)
		hbr = ::CreateSolidBrush (m_colors [_cIdx].col);
	return hbr;
}

HPEN CColors::GetPen (size_t _cIdx, int _nStyle, size_t _cWidth) const {
	HPEN & hpen = m_colors [_cIdx].hpen;
	if (hpen == NULL)
		hpen = ::CreatePen (_nStyle, _cWidth, m_colors [_cIdx].col);
	return hpen;
}

///////////////////////////////////////////////////////

void CColors::LoadFromSetting (const char * _strSetting, const COLORREF * _pDefaultColors, size_t _cColors) {
	const size_t cSize = GetSettingLen (_strSetting);
	const size_t cColors = cSize/sizeof (DWORD);
	if (cColors != _cColors) {
		SetColors (_pDefaultColors, _cColors);
		return;
	}

	COLORREF * const pColors = (COLORREF *) alloca (_cColors*sizeof (COLORREF));
	GetSetting (_strSetting, pColors, _cColors*sizeof (COLORREF));

	SetColors (pColors, _cColors);
}

void CColors::SaveToSetting (const char * _strSetting) const {
	const size_t cColors = GetColors ();
	COLORREF * const pColors = (COLORREF *) alloca (cColors*sizeof (COLORREF));

	for (size_t c = 0; c < cColors; ++ c)
		pColors [c] = GetColor (c);

	SaveSetting (_strSetting, pColors, cColors*sizeof (COLORREF));
}

///////////////////////////////////////////////////////

# include "Dialog.h"
# include "ListView.h"
# include "SelectColor.h"

class CEditColors : public CDialog {
  public:
	CEditColors (CColors & _colors, const COLORREF * _pDefaultColors, const char ** _strColorNames, size_t _cColors) :
		CDialog (IDD_EDIT_COLORS),
		m_colors (_colors),
		m_pDefaultColors (_pDefaultColors),
		m_strColorNames (_strColorNames),
		m_cColors (_cColors)
	{
		const size_t cColors = m_colors.GetColors ();
		m_NewColors.resize (cColors);
		for (size_t c = 0; c < cColors; ++ c)
			m_NewColors [c] = m_colors.GetColor (c);
	}

	virtual bool OnInit (HWND _hwndFocus) {
		// List.
		m_hList = GetDlgItem (IDC_LIST);

		ListView_SetExtendedListViewStyleEx (m_hList, LVS_EX_FULLROWSELECT, LVS_EX_FULLROWSELECT);
		AddColumn (m_hList, 0, "Description");
		AddColumn (m_hList, 1, "RGB");
		_UpdateList ();

		// Edit.
		EnableDlgItem (IDC_EDIT, false);
		// OK.
		EnableDlgItem (IDOK,     false);

		return true;
	}

	virtual void OnCommand (WORD _wCmd, WORD _wNotifyCode, HWND _hwndCtl) {
		switch (_wCmd) {
			case IDC_EDIT: {
				const size_t cSel = ListView_GetSelectionMark (m_hList);
				if (cSel == -1 || cSel >= m_colors.GetColors () || cSel >= m_NewColors.size ())
					break;
				COLORREF col = m_colors.GetColor (cSel);
				if (SelectColor (m_hWnd, col)) {
					m_NewColors [cSel] = col;
					//ListView_RedrawItems (m_hList, 0, ListView_GetItemCount (m_hList) - 1);
					_UpdateList ();
					EnableDlgItem (IDOK, true);
				}
				break;
			}

			case IDC_RESTORE_DEFAULTS: {
				for (size_t c = 0; c < m_cColors; ++ c)
					m_NewColors [c] = m_pDefaultColors [c];

				_UpdateList ();
				EnableDlgItem (IDOK, true);

				break;
			}

			case IDOK: {
				const size_t cColors = __min (m_colors.GetColors (), m_NewColors.size ());
				for (size_t c = 0; c < cColors; ++ c)
					m_colors.SetColor (c, m_NewColors [c]);
				
				EndDialog (0);
				break;
			}

			case IDCANCEL:
				EndDialog (1);
				break;
		}
	}

	virtual bool OnNotify (int _idCtrl, NMHDR * _pInfo) {
		switch (_pInfo->code) {
			case NM_CUSTOMDRAW: {
				NMLVCUSTOMDRAW * const pInfo2 = reinterpret_cast<NMLVCUSTOMDRAW *> (_pInfo);
				if (pInfo2->nmcd.dwDrawStage == CDDS_PREPAINT) {
					SetMsgResult (CDRF_NOTIFYITEMDRAW);
					return true;
				} else if (pInfo2->nmcd.dwDrawStage == CDDS_ITEMPREPAINT) {
					if (pInfo2->nmcd.dwItemSpec >= m_NewColors.size ())
						return false;
					pInfo2->clrTextBk = m_NewColors [pInfo2->nmcd.dwItemSpec];
					pInfo2->clrText = GetContrastColor (pInfo2->clrTextBk);
					SetMsgResult (CDRF_NEWFONT);
					return true;
				}
				break;
			}

			case LVN_ITEMCHANGED: {
				const NMLISTVIEW * const pInfo2 = reinterpret_cast<const NMLISTVIEW *> (_pInfo);
				if (pInfo2->uNewState & LVIS_SELECTED)
					EnableDlgItem (IDC_EDIT, true);
				break;
			}

			case NM_RETURN:
			case NM_DBLCLK:
				SendCommand (IDC_EDIT);
				break;
		}

		return false;
	}

  private:
	CColors & m_colors;
	const COLORREF * const m_pDefaultColors;
	const char ** const m_strColorNames;
	const size_t m_cColors;

	std::vector<COLORREF> m_NewColors;

	HWND m_hList;

	void _UpdateList () {
		ListView_DeleteAllItems (m_hList);

		const size_t cColors = __min (m_NewColors.size (), m_cColors);
		for (size_t c = 0; c < cColors; ++ c) {
			InsertItem (m_hList, c, c, "%s", m_strColorNames [c]);
			SetSubItemText (m_hList, c, 1, "#%06X", m_NewColors [c]);
		}

		AutoSizeColumns (m_hList);
	}
};

bool CColors::Adjust (HWND _hWnd, const COLORREF * _pDefaultColors, const char ** _strColorNames, size_t _cColors) {
	assert (_cColors == GetColors ());
	CEditColors ecd (* this, _pDefaultColors, _strColorNames, _cColors);
	return ecd.ShowModal (_hWnd) == 0;
}
